/*
 *  Copyright 2010 INFN - APE group
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#pragma once

#include <cuos/config.h>

namespace cuos
{

    namespace system_service
    {
        enum sys {
            sys_null = 0,
            sys_open,
            sys_close,
            sys_write,
            sys_read,
            sys_mpi_send,
            sys_mpi_isend,
            sys_mpi_bsend,
            sys_mpi_recv,
            sys_mpi_irecv,
            sys_mpi_test,
            sys_mpi_wait,
            sys_mpi_reduce,
        };

        struct param {
            enum tag_t {
                tag_none   = 0,
                tag_int    = 1,
                tag_uint   = 2,
                tag_long   = 3,
                tag_ulong  = 4,
                tag_float  = 5,
                tag_double = 6,
                tag_ptr    = 7,
                num_tags
            };
            int               tag;
            uint              count;
            union {
                int           si;
                uint          ui;
                long          sl;
                unsigned long ul;
                float         f;
                double        d;
                void         *ptr;
            };
        };

#if 0
        // compiler BUG
        #define CUOS_INIT_PARAM                 { param::tag_none, 0, 0 }
        static inline __host__ __device__ param cuos_make_none_param() {
            param p = CUOS_INIT_PARAM;
            return p;
        }
#else
        static inline __host__ __device__ param cuos_make_none_param() {
            param p;
            p.tag = param::tag_none;
            p.count = 0;
            p.ptr = 0;            
            return p;
        }
#endif

        static inline __host__ __device__ param cuos_make_ptr_param(void *ptr, size_t count) {
            param p;
            p.tag = param::tag_ptr;
            p.count = count;
            p.ptr = ptr;
            return p;
        }

        static inline __host__ __device__ param cuos_make_int_param(int val) {
            param p;
            p.tag = param::tag_int;
            p.count = 1;
            p.si = val;
            return p;
        }

        static inline __host__ __device__ param cuos_make_uint_param(unsigned int val) {
            param p;
            p.tag = param::tag_int;
            p.count = 1;
            p.ui = val;
            return p;
        }

        struct request {
            enum {
                // bit values for flags field
                flag_pending      = 1<<0, 
                flag_need_reply   = 1<<1,
                flag_request      = 1<<2,
                // max number of params for syscall invocation 
                max_params        = 8
            };
            int    id;
            uint   serial;
            uint   n_params;
            uint   flags;
            param  params[max_params];
            //param  retval;
        };

        struct reply {
            uint   serial;
            uint   flags; // undefined id, ...
            param  retval;
#if CUOS_REPLY_DUMMY_WORDS
            uint   dummy[6];
#endif
        };

    } // end namespace system_service

    typedef system_service::sys     sys_id_t;
    typedef system_service::request sys_req_t;
    typedef system_service::reply   sys_rep_t;

    namespace host {
        __host__ void dump(const cuos::sys_req_t &req);
    }

} // end namespace cuos


/*
 * Local variables:
 *  mode: c++
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 *  indent-tabs-mode: nil
 * End:
 */
